package br.com.winesys.geta.editor;

import java.awt.Cursor;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.swing.JComponent;
import javax.validation.ConstraintViolation;
import br.com.winesys.geta.databinding.Binder;
import br.com.winesys.geta.databinding.Field;

public abstract class AbstractObjectEditor<Entity> implements Editor<Entity> {

	private JComponent component;
	private Map<String, Field> fieldMap = new LinkedHashMap<String, Field>();
	private List<WarningDecorator> decorators = new LinkedList<WarningDecorator>();
	private Entity object;

	public AbstractObjectEditor(JComponent component) {
		this.component = component;
		AbstractObjectEditor.this.createFields();
	}

	@Override
	public void setEnabled(boolean enabled) {
		this.component.setEnabled(enabled);
		for (Field field : this.getFields()) {
			field.getEditor().setFocusable(enabled);
			field.getEditor().setEnabled(enabled);
		}
	}

	
	@Override
	public void cleanValidation(){
		List<WarningDecorator> decoratorsList = new LinkedList<WarningDecorator>(this.decorators);
		for (WarningDecorator decorator : decoratorsList) {
			decorator.dispose();
			this.decorators.remove(decorator);
		}
	}
	
	@Override
	public boolean validate() {
		List<WarningDecorator> decoratorsList = new LinkedList<WarningDecorator>(this.decorators);
		for (WarningDecorator decorator : decoratorsList) {
			decorator.dispose();
			this.decorators.remove(decorator);
		}
		Map<String, Set<ConstraintViolation<Entity>>> errors = Binder.getInstance().validate((Class<Entity>) this.object.getClass(), getFields());
		if (!errors.isEmpty()) {
			for (String fieldName : errors.keySet()) {
				StringBuilder messageBuilder = new StringBuilder();
				for (ConstraintViolation<Entity> erro : errors.get(fieldName)) {
					messageBuilder.append(erro.getMessage()).append("\n");
				}
				Field field = this.fieldMap.get(fieldName);
				WarningDecorator decorator = new WarningDecorator(field.getEditor());
				decorator.setCursor(Cursor.getDefaultCursor());
				decorator.setToolTipText(messageBuilder.toString());
				this.decorators.add(decorator);
			}
			return false;
		}

		return true;
	}

	@Override
	public JComponent getComponent() {
		return this.component;
	}

	@Override
	public void setObject(Entity object) {
		this.object = object;
		Binder.getInstance().fillFields(this.getFields(), this.object);
	}

	@Override
	public Entity getObject() {
		Binder.getInstance().fillBean(this.getFields(), this.object);
		return this.object;
	}

	@Override
	public void setProperties(Map<String, Object> properties) {
		Binder.getInstance().fillFields(this.getFields(), properties);
	}

	@Override
	public Map<String, Object> getProperties() {
		Map<String, Object> result = new TreeMap<String, Object>();
		Binder.getInstance().fillMap(this.getFields(), result);
		return result;
	}

	public void setProperty(String property, Object value) {
		Field field = this.fieldMap.get(property);
		if (field != null) {
			Binder.getInstance().setComponentValue(field.getEditor(), value);
		}
	}

	public void addField(Field field) {
		this.fieldMap.put(field.getName(), field);
	}

	public Field[] getFields() {
		return this.fieldMap.values().toArray(new Field[this.fieldMap.size()]);
	}
	
	public Field getField(String property){
		return this.fieldMap.get(property);
	}

	protected abstract void createFields();
}